﻿using System;
using System.Reflection;
using NLite;
using NLite.Internal;
using NLite.Mapping;
using NLite.Mapping.Internal;

namespace NLite
{
    /// <summary>
    /// 
    /// </summary>
    public sealed class Mapper
    {

        static readonly  MethodInfo InternMap_Method = typeof(Mapper).GetMethod("InternalMap", BindingFlags.Static | BindingFlags.NonPublic);

        const string key = "NLite_MappingEngine";


        static MapingEngine _current;

        static Mapper()
        {
            _current = new MapingEngine();
            ServiceRegistry.Current.RegisterInstance<IMappingEngine, MapingEngine>(_current);
            Current = _current;
        }

        /// <summary>
        /// 得到当前活动的MappingEngine
        /// </summary>
        public static IMappingEngine Current { get; set; }
        //{
        //    get
        //    {
        //        var o = NLiteEnvironment.IsWeb ? NLiteEnvironment.Application[key] as IMappingEngine : _current;
        //        if (o == null)
        //        {
        //            o = 
        //        }
        //    }
        //    set
        //    {
        //        if (NLiteEnvironment.IsWeb)
        //            NLiteEnvironment.Application[key] = value;
        //        else
        //            _current = value;
        //    }
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="from"></param>
        /// <param name="fromType"></param>
        /// <param name="toType"></param>
        /// <returns></returns>
        public static object Map(object from, Type fromType, Type toType)
        {
            Assumes.NotNull<Type>(toType);

            if (toType == Types.Object)
                return from;

            if (from != null)
                fromType = from.GetType();
            if(from == DBNull.Value)
            	return ObjectCreator.Create(toType);

            return InternMap_Method.MakeGenericMethod(fromType, toType).Invoke(null, new object[] { from });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TFrom"></typeparam>
        /// <typeparam name="TTo"></typeparam>
        /// <param name="from"></param>
        /// <returns></returns>
        public static TTo Map<TFrom, TTo>(TFrom from)
        {
            return CreateMapper<TFrom, TTo>().Map(from);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TFrom"></typeparam>
        /// <typeparam name="TTo"></typeparam>
        /// <param name="from"></param>
        /// <param name="to"></param>
        public static void Map<TFrom, TTo>(TFrom from,ref TTo to)
        {
            Current.CreateMapper<TFrom, TTo>().Map(from,ref  to);
        }

        private static TTo InternalMap<TFrom, TTo>(TFrom from)
        {
            return Current.CreateMapper<TFrom, TTo>().Map(from);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TFrom"></typeparam>
        /// <typeparam name="TTo"></typeparam>
        /// <returns></returns>
        public static IMapper<TFrom, TTo> CreateMapper<TFrom, TTo>()
        {
            return Current.CreateMapper<TFrom, TTo>();
        }

        /// <summary>
        /// 
        /// </summary>
        public static void Reset()
        {
            Current.MapperRegistry.Clear();
        }
    }
}
